package com.free.utils;

import com.free.exception.SystemException;
import org.apache.commons.lang3.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * <p>
 * 功能概述:
 * </p>
 * <p>
 * 功能详述:
 * </p>
 */
public class DateUtils {
    /*========================================================================*
     *                         Public Fields (公共属性)
     *========================================================================*/

    /*========================================================================*
     *                         Private Fields (私有属性)
     *========================================================================*/

    /*========================================================================*
     *                         Construct Methods (构造方法)
     *========================================================================*/

    /*========================================================================*
     *                         Public Methods (公有方法)
     *========================================================================*/

    /**
     * 获取当前时间
     */
    public static Date getCurrentDate()
    {
        return new Date();
    }

    /**
     * 字符串转日期
     *
     * @param str 日期字符串
     * @param format 格式化的类型
     *
     * @return 格式化的日期，字符串为空的情况返回null
     */
    public static Date convert2Date(String str, FormatEnum format) throws SystemException {
        if (StringUtils.isBlank(str) || format == null)
        {
            return null;
        }

        SimpleDateFormat dateformat = new SimpleDateFormat(format.getValue());
        try
        {
            return dateformat.parse(str);
        }
        catch (ParseException e)
        {
            throw new SystemException("DateUtils.convert2Date 发生异常", e);
        }
    }

    /**
     * 日期转字符串
     *
     * @param date 日期
     * @param format 格式化的类型
     *
     * @return 格式化的日期字符串，日期为空的情况返回null
     */
    public static String convert2String(Date date, FormatEnum format)
    {
        if (date == null || format == null)
        {
            return null;
        }

        SimpleDateFormat dateformat = new SimpleDateFormat(format.getValue());

        return dateformat.format(date);
    }

    /**
     * 日期转为字符串
     * @param date
     * @param format
     * @return
     */
    public static  String convert2String(Date date, String format){
        if (date == null || format == null)
        {
            return null;
        }
        SimpleDateFormat dateformat = new SimpleDateFormat(format);
        return dateformat.format(date);
    }


    /**
     * 返回指定格式的当前日期
     *
     * @param format 日期格式
     *
     * @return 指定格式的当前日期
     */
    public static String now(FormatEnum format)
    {
        return now(format.getValue());
    }

    /**
     * 返回指定格式的当前日期
     * @param format 日期格式
     * @return
     */
    public static String now(String format){
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(format));
    }


    public static Date nowDate(){
        LocalDate localDate =  LocalDate.now();
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
        return Date.from(instant);
    }

    /**
     * 返回指定格式的当前日期
     *
     * @param format 日期格式
     *
     * @return 指定格式的当前日期
     */
    public static Date nowDate(FormatEnum format) throws SystemException {
        return convert2Date(now(format), format);
    }


    /**
     * 获得当前日期的偏移日期
     * @return
     */
    public static String getCurrentOffsetDay(int day)
    {
        return getCurrentOffsetDay(day, FormatEnum.yyyy_MM_dd);
    }


    /**
     * 获得当前日期的偏移日期
     * @return
     */
    public static String getCurrentOffsetDay(int day, FormatEnum format)
    {
        LocalDateTime localDateTime = LocalDateTime.now().plusDays(day);
        return localDateTime.format(DateTimeFormatter.ofPattern(format.getValue()));
    }

    public static boolean isLeapYear(int year){
        if(year%4==0 && year%100!=0){
            return true;
        }
        if(year%400 == 0){
            return true;
        }
        return false;
    }

    public static Date getMonthLastDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, calendar
                .getActualMaximum(Calendar.DAY_OF_MONTH));
        return calendar.getTime();
    }

    public static Date getMonthFirstDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, calendar
                .getActualMinimum(Calendar.DAY_OF_MONTH));
        return calendar.getTime();
    }

    /**
     * 获得两个时间差的秒数
     * @param startTime
     * @param endTime
     * @return
     */
    public static long getDiffTimeOfSeconds(Date startTime, Date endTime) {

        LocalTime start = transferDateToLocalTime(startTime);
        LocalTime end = transferDateToLocalTime(endTime);
        return ChronoUnit.SECONDS.between(start, end);
    }

    /**
     * 获取两个时间差的分钟数
     * @param startTime
     * @param endTime
     * @return
     */
    public static long getDiffTimeOfMinutes(Date startTime, Date endTime)
    {
        LocalTime start = transferDateToLocalTime(startTime);
        LocalTime end = transferDateToLocalTime(endTime);
        return ChronoUnit.MINUTES.between(start, end);
    }


    /**
     * 获取两个时间差的天数
     * 【参与计算的只有日期部分，时间部分不参与计算】
     *
     * @param startTime
     * @param endTime
     * @return
     *
     * 例1：
     *      startTime = 2017-10-01 13:37:00
     *      endTime   = 2017-10-11 13:37:00
     *      return    = 10
     *
     * 例2：
     *      startTime = 2017-10-11 13:37:00
     *      endTime   = 2017-10-01 13:37:00
     *      return    = -10
     *
     * 例3：
     *      startTime = 2017-10-11 13:37:00
     *      endTime   = 2017-10-11 13:37:00
     *      return    = 0
     *
     */
    public static long getDiffTimeOfDays(Date startTime, Date endTime)
    {
        LocalDate start = transferDateToLocalDate(startTime);
        LocalDate end = transferDateToLocalDate(endTime);
        return ChronoUnit.DAYS.between(start, end);
    }

    public static long getDiffTimeOfMonth(Date startTime, Date endTime){
        LocalDate start = transferDateToLocalDate(startTime);
        LocalDate end = transferDateToLocalDate(endTime);
        return ChronoUnit.MONTHS.between(start, end);
    }

    /**
     * 增加天数
     * 例如    currentDate = 2017-09-01 , days = 2 . return 2017-09-03
     *     currentDate = 2017-08-31 , days = 2 . return 2017-09-02
     * @param currentDate
     * @param days
     * @return
     */
    public static Date nextDate(Date currentDate, int days)
    {
        if (null == currentDate)
        {
            return null;
        }

        Calendar calendar = new GregorianCalendar();

        calendar.setTime(currentDate);

        calendar.add(Calendar.DATE, days); //把日期往后增加一天.整数往后推,负数往前移动

        return calendar.getTime();
    }

    public static Date nextMinute(Date currentDate, int minutes){
        if (null == currentDate)
        {
            return null;
        }

        Calendar calendar = new GregorianCalendar();

        calendar.setTime(currentDate);

        calendar.add(Calendar.MINUTE, minutes); //把日期往后增加一天.整数往后推,负数往前移动

        return calendar.getTime();
    }

    public static Date nextSecond(Date currentDate, int seconds){
        if (null == currentDate)
        {
            return null;
        }

        Calendar calendar = new GregorianCalendar();

        calendar.setTime(currentDate);

        calendar.add(Calendar.SECOND, seconds); //把日期往后增加一天.整数往后推,负数往前移动

        return calendar.getTime();
    }
    /*========================================================================*
     *                         Private Methods (私有方法)
     *========================================================================*/

    public enum FormatEnum
    {
        HHMM("HH:mm"),yyyyMM("yyyyMM"),yyyy_MM_dd("yyyy-MM-dd"), yyyyMMdd("yyyyMMdd"),yyyy_MM_dd_T_HH_mm_ss("yyyy-MM-ddTHH:mm:ss"), yyyy_MM_dd_HH_mm_ss("yyyy-MM-dd HH:mm:ss"), yyyyMMddHHmmss("yyyyMMddHHmmss"), yyyy_M_d_HH_mm(
                "yyyy/M/d HH:mm"),yyyyMMDDHHMMSS_CN("yyyy年MM月dd日HH时mm分ss秒"),yyyyMMddHHmm("yyyyMMddHHmm"),yyyyMMddHHmmssSSS("yyyyMMddHHmmssSSS"),yyyyspMMspdd("yyyy/MM/dd"), yyyyspMMspdd_HH_mm_ss("yyyy/MM/dd HH:mm:ss"),yyyy_MM_dd_HH_mm("yyyy-MM-dd HH:mm");
        String value;


        FormatEnum(String value)
        {
            this.value = value;
        }


        public String getValue()
        {
            return value;
        }


        public void setValue(String value)
        {
            this.value = value;
        }
    }

    /**
     * 转换日期类型：Date --> LocalTime
     * @param date
     * @return
     */
    public static LocalTime transferDateToLocalTime(Date date)
    {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        return localDateTime.toLocalTime();
    }


    /**
     * 转换日期类型：Date --> LocalTime
     * @param date
     * @return
     */
    private static LocalDate transferDateToLocalDate(Date date)
    {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        return localDateTime.toLocalDate();
    }
}
